// node实现子进程有一个自带的模块 child_process
// 可以创建一个进程为我们服务 不会影响当前node的事件环 他们两个各自独立
// 为什么要实现多进程
// 多核cpu 如果在node里只开一个进程 只会占用1个cpu
/*
在Node.js中，只有一个线程执行所有操作，如果某个操作需要大量消耗CPU资源的情况下，后续操作都需要等待。
在Node.js中，提供了一个child_process模块,通过它可以开启多个子进程，在多个子进程之间可以共享内存空间，可以通过子进程的互相通信来实现信息的交换。
*/

let os = require('os').cpus();
// console.log(os.length); //16

//--- --- ---


// 集群 一般一个进程分一个核 node就八核八线程

/* child_process下的四个方法
1.spawn 产卵
2.fork 叉子
3.exec 执行
4.execFile 执行文件
*/
let {spawn} = require('child_process');
let path = require('path');
// node a.js a b c
// process.cwd();
//child_process.spawn(command,[args],[options]);
let child = spawn('node',['1.test.js','a','b','c'],{ //←这个不会流入子进程的stdin，因为此时子进程还没有起起来，只能通过process.argv拿到
  cwd:path.join(__dirname,'test') //设置当前工作目录，即在命令行中哪个位置执行上面的spawn指定的命令

  // ,stdio:'inherit' //表示子进程的标准输入输出都用父进程的，如果不写这个的话，那每个进程的标准输入输出都是各自自己的(即pipe)
  ,stdio:[process.stdin,process.stdout,process.stderr] //等同于上面
  // ,stdio:[0,1,2] //同上

  /*
    stdio的值可以是一个数值，即文件描述符fd，上面的0、1、2即对应process.stdin、process.stdout、process.stderr三个可读可写流
    故stdio数组中可以放stream，也可以放stream对应的fd(一个stream会对应一个fd 参考11stream ReadStream)
  */

  /* pipe
    pipe 在父进程和子进程之间创建一个管道
    ，父进程可以通过子进程的stdio[0]访问子进程的标准输入
    ，通过stdio[1]访问标准输出,stdio[2]访问错误输出
  */
  // ,stdio:'pipe' //【默认值】 在父子进程之间建立了一个管道，流
  // ,stdio:['pipe','pipe','pipe']  //同上
  // ,stdio:null //或则undefined时，效果同上

  // [0,1,2]和'pipe' 是有区别的 pipe是用来通信的，而inherit只是单纯给子进程共享一个终端设备，并不能有效的监听控制子进程的输入输出，值为pipe时，每个子进程都有自己独立的标准输入输出错误输出
  // 如果你想在一个子进程中监听到别的进程给自己的输入 推荐将process.stdin所占的stdio坑位置为pipe，这样就能on('data了
  // 如果使用inherit的方式，我们不能在父进程中对子进程的输入输出进行管控(监听)
  // 比如我们 要想child.stdin.on('data' 就需要将0的坑位置为pipe
  //要想child.stdout.on('data' 就需要将1的坑位置为pipe
  //要想child.stderr.on('data' 就需要将2的坑位置为pipe(这样在子进程的文件里throw的error 就会被父进程child.stderr.on('data'监听到)


});

console.log('--------'); /* spawn是异步的 */

// child.stdout.on('data',function(data){
//   console.log('child:data.toString():',data.toString());
// });


//pipe模式下如果不主动监听就不会主动输出到主进程的的stdout
// child.stderr.on('data', function (err) {
//   console.log('child发生错误',err.toString());
// });

//当子进程所有输入输出都终止时，会触发子进程对象的close事件。
//code 为0表示正常推出，为null表示异常退出
//当在父进程中关闭子进程时，signal参数值为父进程发给子进程的信号名称
child.on('exit', function (code,signal) {
  console.log('child exit');
});

// 父进程还可以使用kill方法向子进程发送信号,参数为描述该信号的字符串，默认参数值为SIGTERM
// SIGTERM 程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理. 通常用来要求程序自己正常退出
// child.kill('SIGTERM'); //这里用的话会子进程还没有启动，会放弃掉启动，并触发close事件，不会运行任何spawn(spawn是异步代码)

// 当子进程退出时，触发子进程对象的exit事件
// 因为多个进程可能会共享i 个输入/输出，所以当子进程退出时，子进程的输入/输出可能并未终止
child.on('close', function (code,signal) {
  console.log('child close');
  console.log('退出代码为:', code);
  console.log('接受到的信号为:', signal);
});

//如果子进程开启失败，那么将会触发子进程对象的error事件
child.on('error',function(err){
  console.log(err);
})
